
#include <utils/bitmap.h>
#include <mm/kmalloc.h>
#include <utils/string.h>

#define INDEX_FROM_BIT(a) ((a)/32)
#define OFFSET_FROM_BIT(a) ((a)%32)

void bitmap_set(bitmap *bm, uint32 bit) {
    if(bit < bm->num_bits) {
        uint32 idx = INDEX_FROM_BIT(bit);
        uint32 off = OFFSET_FROM_BIT(bit);
        bm->bits[idx] |= (0x1 << off);
    }
}

void bitmap_clear(bitmap *bm, uint32 bit) {
    if(bit < bm->num_bits) {
        uint32 idx = INDEX_FROM_BIT(bit);
        uint32 off = OFFSET_FROM_BIT(bit);
        bm->bits[idx] &= ~(0x1 << off);
    }
}

// this returns 0 if bit is not set
// != 0 otherwise.
// No warranty for that value to be 1
uint32 bitmap_get(bitmap *bm, uint32 bit) {
    if(bit < bm->num_bits) {
        uint32 idx = INDEX_FROM_BIT(bit);
        uint32 off = OFFSET_FROM_BIT(bit);
        return (bm->bits[idx] & (0x1 << off));
    }
    return 0;
}

// Return first 0 bit index
uint32 bitmap_get_first_available(bitmap *bm) {
    uint32 i, j;
    for(i = 0; i < INDEX_FROM_BIT(bm->num_bits); i++) {
        if(bm->bits[i] != 0xFFFFFFFF) {
            for (j = 0;j < 32; j++) {
                if(!(bm->bits[i] & (0x1 << j))){
                    return i*32 + j;
                }
            }
        }
    }
    return -1; // not found
}

bitmap *bitmap_new(uint32 num_bits) {
    bitmap *bm = (bitmap*)kmalloc(sizeof(bitmap));
    bm->bits = (uint32*)kmalloc(num_bits / 32);
    memset(bm->bits, 0, num_bits / 32);
    bm->num_bits = num_bits;
    
    return bm;
}

